﻿using System;
using System.IO;
using ePipe;
using System.Threading.Tasks;

namespace Letter.Net.Tcp;

/// <summary>
/// A helper for wrapping a Stream decorator from an <see cref="IDuplexPipe"/>.
/// </summary>
/// <typeparam name="TStream"></typeparam>
internal class DuplexPipeStreamAdapter<TStream> : DuplexPipeStream, IDuplexPipe<byte> where TStream : Stream
{
    private bool _disposed;
    private readonly object _disposeLock = new object();
    

    public DuplexPipeStreamAdapter(IDuplexPipe<byte> duplexPipe, Func<Stream, TStream> createStream) 
        : this(duplexPipe, new StreamPipeReaderOptions(leaveOpen: true), new StreamPipeWriterOptions(leaveOpen: true), createStream)
    {
    }

    public DuplexPipeStreamAdapter(IDuplexPipe<byte> duplexPipe, StreamPipeReaderOptions readerOptions, StreamPipeWriterOptions writerOptions, Func<Stream, TStream> createStream) 
        : base(duplexPipe.Reader, duplexPipe.Writer)
    {
        var stream = createStream(this);
        Stream = stream;

        this.input = Pipeline.CreateStreamPipeReader(stream, readerOptions);
        this.output = Pipeline.CreateStreamPipeWriter(stream, writerOptions);
    }

    private IPipeReader<byte> input;
    private IPipeWriter<byte> output;
    
    public TStream Stream { get; }


    IPipeReader<byte> IDuplexPipe<byte>.Reader => this.input;
    IPipeWriter<byte> IDuplexPipe<byte>.Writer => this.output;

    public override ValueTask DisposeAsync()
    {
        lock (_disposeLock)
        {
            if (_disposed)
            {
                return default;
            }
            _disposed = true;
        }
        
        this.Stream.Dispose();
        return base.DisposeAsync();
    }
}
